The interview now says what the two answers changed - #61
Merged
Conversation
Found by running the app, which nothing else on this branch could do. The founder answered "how long does your money last" and "any constraint the room must not propose", and then the conversation simply stopped. No acknowledgement, no visible change. Their words: it feels like it did nothing. That reading was fair. The first-run interview ends by seeding byte's greeting; this one deliberately suppresses that — and nothing was put in its place. Neither answer is displayed anywhere in the app, so a closing line is the only evidence they landed at all. The close quotes both answers back rather than thanking the founder abstractly, because the point is to show the specifics were heard, and it names what they change: the room drops proposals that eat too much of the runway, and stops suggesting what has already been ruled out. A founder has no way to infer that runway is what makes a three-week proposal unacceptable. Skipping both is handled separately and honestly — it says recommendations stay more general, rather than claiming an effect it did not get. One existing test asserted "no greeting" by checking the last message's role was .me, which conflated "no welcome" with "no companion message at all". Narrowed to assert what it means: that this particular greeting text is absent. Its comment already recorded being rewritten once before for the same reason. VirtualCompanyInterviewTests 19/19 (2 new), CompanyStoreChatTests 24/24, CompanyStoreOnboardingTests 11/11, EnrichInterviewTests 8/8, CompanyStoreVirtualCompanyTests 15/15, build green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Found in the app. byte replied with a run_task_id and no text, so the store wrote
its lead-in — "on it, putting that together now" — and then nothing ever arrived.
No draft, no error, no explanation. Forever.
`handleRunTaskId` had three silent early returns, and the lead-in is written
BEFORE any of them run:
guard let runId,
let task = company.tasks.first(where: { $0.id == runId }),
RoadmapEngine.status(for: task, in: company.tasks) == .codepetCanDo
else { return }
So byte promised and a guard quietly withdrew it. Worth noting `produceDraftInline`
already had an honest failure path — its own comment promises "an honest couldn't
generate bubble" — but this returned before reaching it.
Every refusal knows exactly why, and `TaskStatus` distinguishes five cases, three
of which are the founder's own move rather than a failure. So each one says so, and
names the task: the founder did not choose it, byte did, so "that one" is not
enough to act on.
- needsApproval → a draft is already waiting; redoing it would overwrite that
- done → already finished; open it if you want it redone
- blocked → waiting on another task, or its phase hasn't opened
- needsYou → yours to do, and byte offers to walk you through it
- task missing → the id no longer matches the roadmap; ask which one
A nil run_task_id — the overwhelmingly common case — still says nothing.
Two existing tests asserted `chatMessages.count == 2` with the comment "me +
lead-in only": they encoded the silence itself. Updated to assert the reason is
given, plus a new test covering all four refusal reasons and that each names its
task.
CompanyStoreChatRunTests 15/15, CompanyStoreChatTests 24/24,
CompanyStoreRunTaskTests 17/17, CompanyStoreVirtualCompanyTests 15/15,
VirtualCompanyInterviewTests 19/19, ChatTailActionTests 5/5, build green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found by running the app — which nothing else on the feature branch could do.
The founder answered "how long does your money last?" and "any constraint the room must not propose?", and then the conversation just stopped. No acknowledgement, no visible change. Their words: it feels like it did nothing.
That reading was fair.
Why it was silent
The first-run interview ends by seeding byte's greeting. This one deliberately suppresses that — welcoming a founder right after a mid-session pricing question would read as amnesia — and nothing was put in its place:
The chat was not blocked, either:
isChatBusyisisCompanionTyping || isStreaming || isFanningOut, and the interview sets none of them. It was silent, not stuck — which is harder to diagnose as a user, because nothing looks broken.What the close does
It quotes both answers back rather than thanking the founder abstractly, so the specifics are visibly heard, and it names what they change: the room drops proposals that eat too much of the remaining runway, and stops suggesting what has already been ruled out. A founder has no way to infer that runway is the thing that makes a three-week proposal unacceptable.
Skipping both is handled separately and honestly — it says recommendations stay more general, rather than claiming an effect it did not get.
A test that asserted more than it meant
One existing test proved "no greeting" by checking the last message's role was
.me, conflating no welcome with no companion message at all. Narrowed to assert what it means: that this particular greeting text is absent. Its own comment already recorded being rewritten once before, for the same reason.Verified
VirtualCompanyInterviewTests19/19 (2 new) ·CompanyStoreChatTests24/24 ·CompanyStoreOnboardingTests11/11 ·EnrichInterviewTests8/8 ·CompanyStoreVirtualCompanyTests15/15 · build green.The larger finding this exposed, not fixed here
runwayandconstraintsare invisible after they are answered — but so aregoal,tractionandproblem, the three fields the existing onboarding interview collects. None of the five appear anywhere in the UI; they only feed prompt context. The brief editor in Settings exposesfounderName,role,tech,stage,oneLiner,audienceand nothing the interviews gather.So the pattern is already ask → the answer dissolves into context → the founder never sees it again. This feature only made it visible, by asking mid-session where the silence is noticeable rather than during onboarding where it is not.
A small "what the room knows about you" surface would fix all five, and is a product decision worth making deliberately rather than as a side effect of this PR.
🤖 Generated with Claude Code